/*
 * Copyright (C) 2019-2020 Alibaba Group Holding Limited
 */
#include "app_main.h"
#include "app_pwm.h"
#include <drv/pwm.h>
#include "devices/device.h"
#define TAG "app"

#define DEVICE_LED_NAME "ledrgb"
#define PWM_PERIOD 100

enum led_color_set_e {
    LED_COLOR_WHITE = 0,
    LED_COLOR_YELLOW,
    LED_COLOR_NATURE,
    LED_COLOR_NUM,
};

typedef struct {
    uint8_t red;
    uint8_t green;
    uint8_t blue;
} led_rgb_t;

typedef struct pwm_led {
    uint8_t status;     /* 0 - stop, 1 - start */
    int32_t brightness; /* 10 - 100 */
    // uint8_t pinr;
    // uint8_t ping;
    // uint8_t pinb;
    uint8_t chn_r;
    uint8_t chn_g;
    uint8_t chn_b;
    led_rgb_t  rgb_val;
    // pin_func_e pin_func;
} pwm_led_t;

static aos_dev_t *led_dev      = NULL;
static int        g_app_led_en = 1;
#ifdef APP_PWM_EN
// // PWM0
// static pwm_led_t  g_pwm_ledr_ctx = {0, 60, PWM0_PIN, PWM0_CH, PWM0_PIN_FUNC};
// // PWM1
// static pwm_led_t  g_pwm_ledg_ctx = {0, 60, PWM1_PIN, PWM1_CH, PWM1_PIN_FUNC};
// // PWM2
// static pwm_led_t  g_pwm_ledb_ctx = {0, 60, PWM2_PIN, PWM2_CH, PWM2_PIN_FUNC};
static pwm_led_t  g_pwm_led_ctx = {0, 60, PWM0_CH, PWM1_CH, PWM2_CH};
#else
static pwm_led_t  g_pwm_led_ctx = {0};
#endif

static led_rgb_t led_rgb_series[LED_COLOR_NUM];
// static led_rgb_t g_pwm_led_ctx.rgb_val;

int app_pwm_led_set_stop();

int8_t app_pwm_led_init()
{
    int8_t ret = 0;
    int pwmled_en;

    ret = aos_kv_getint("pwmled_en", &pwmled_en);
    if (ret == 0 && pwmled_en == 0) {
        /* 若没有设置KV,默认使能 */
        LOGE(TAG, "pwm led disabled, use \"kv setint pwmled_en 1\"");
        return -1;
    }

#if defined(BOARD_OFFLINE_AUDIO) && BOARD_OFFLINE_AUDIO
    // switch off threee leds
    app_gpio_write(PWM0_PIN, 0);
    app_gpio_write(PWM1_PIN, 0);
    app_gpio_write(PWM2_PIN, 0);
#endif

    led_rgb_series[LED_COLOR_WHITE].red   = 255;
    led_rgb_series[LED_COLOR_WHITE].green = 220;
    led_rgb_series[LED_COLOR_WHITE].blue  = 220;
    led_rgb_series[LED_COLOR_YELLOW].red   = 255;
    led_rgb_series[LED_COLOR_YELLOW].green = 200;
    led_rgb_series[LED_COLOR_YELLOW].blue  = 0;
    led_rgb_series[LED_COLOR_NATURE].red   = 160;
    led_rgb_series[LED_COLOR_NATURE].green = 160;
    led_rgb_series[LED_COLOR_NATURE].blue  = 255;
    g_pwm_led_ctx.rgb_val = led_rgb_series[LED_COLOR_WHITE];

    int brightness;
    if (aos_kv_getint("led_brightness", &brightness) == 0) {
        g_pwm_led_ctx.brightness = brightness;
    }

    ret = app_pwm_init(PWM0_PIN, PWM0_PIN_FUNC, g_pwm_led_ctx.chn_r);
    aos_check_return_einval(ret == 0);

    ret = app_pwm_init(PWM1_PIN, PWM1_PIN_FUNC, g_pwm_led_ctx.chn_g);
    aos_check_return_einval(ret == 0);

    ret = app_pwm_init(PWM2_PIN, PWM2_PIN_FUNC, g_pwm_led_ctx.chn_b);
    aos_check_return_einval(ret == 0);

    app_pwm_led_set_stop();

    aos_msleep(20);
    ret = app_pwm_start(g_pwm_led_ctx.chn_r);
    aos_check_return_einval(ret == 0);

    ret = app_pwm_start(g_pwm_led_ctx.chn_g);
    aos_check_return_einval(ret == 0);

    ret = app_pwm_start(g_pwm_led_ctx.chn_b);
    aos_check_return_einval(ret == 0);

    g_pwm_led_ctx.status = 0;

    return ret;
}

int app_pwm_led_set_rgb(uint8_t red, uint8_t green, uint8_t blue)
{
    LOGD(TAG, "set led rgb to %d %d %d\n", red, green, blue);

    g_pwm_led_ctx.rgb_val.red     = red;
    g_pwm_led_ctx.rgb_val.green   = green;
    g_pwm_led_ctx.rgb_val.blue    = blue;
    return app_pwm_led_control(1);
}

int app_pwm_led_set_white()
{
    LOGD(TAG, "set led to white");
    return app_pwm_led_set_rgb(led_rgb_series[LED_COLOR_WHITE].red,
                        led_rgb_series[LED_COLOR_WHITE].green,
                        led_rgb_series[LED_COLOR_WHITE].blue);
}

int app_pwm_led_set_yellow()
{
    LOGD(TAG, "set led to yellow");
    return app_pwm_led_set_rgb(led_rgb_series[LED_COLOR_YELLOW].red,
                        led_rgb_series[LED_COLOR_YELLOW].green,
                        led_rgb_series[LED_COLOR_YELLOW].blue);
}

int app_pwm_led_set_nature()
{
    LOGD(TAG, "set led to nature");

    return app_pwm_led_set_rgb(led_rgb_series[LED_COLOR_NATURE].red,
                        led_rgb_series[LED_COLOR_NATURE].green,
                        led_rgb_series[LED_COLOR_NATURE].blue);
}

// int app_

// int8_t app_pwm_led_deinit(void)
// {
//     return app_pwm_deinit();
// }

int app_pwm_led_set_config(int brightness)
{
    int ret;
    int br_red = g_pwm_led_ctx.rgb_val.red * brightness / 255;
    int br_green = g_pwm_led_ctx.rgb_val.green * brightness / 255;
    int br_blue = g_pwm_led_ctx.rgb_val.blue * brightness / 255;

    LOGD(TAG, "set pwm led to %d %d %d", br_red, br_green, br_blue);
#if defined(BOARD_OFFLINE_AUDIO) && BOARD_OFFLINE_AUDIO
    // int ret = app_pwm_config(g_pwm_led_ctx.channel, PWM_PERIOD,  brightness);
    ret = app_pwm_config(g_pwm_led_ctx.chn_r, PWM_PERIOD,  br_red);
    aos_check_return_einval(ret == 0);

    ret = app_pwm_config(g_pwm_led_ctx.chn_g, PWM_PERIOD,  br_green);
    aos_check_return_einval(ret == 0);

    ret = app_pwm_config(g_pwm_led_ctx.chn_b, PWM_PERIOD,  br_blue);
    aos_check_return_einval(ret == 0);
#else
    ret = app_pwm_config(g_pwm_led_ctx.chn_r, PWM_PERIOD,  100 - br_red);
    aos_check_return_einval(ret == 0);

    ret = app_pwm_config(g_pwm_led_ctx.chn_g, PWM_PERIOD,  100 - br_green);
    aos_check_return_einval(ret == 0);

    ret = app_pwm_config(g_pwm_led_ctx.chn_b, PWM_PERIOD,  100 - br_blue);
    aos_check_return_einval(ret == 0);
#endif

    return ret;
}

int app_pwm_led_set_stop()
{
    LOGD(TAG, "PWM led off.");
    return app_pwm_led_set_config(0);
}

int app_pwm_led_set_normal()
{
    LOGD(TAG, "PWM led set to brightness %d", g_pwm_led_ctx.brightness);
    int brightness = g_pwm_led_ctx.brightness;
    if (brightness == PWM_LED_LIGHT_MAX) {
        brightness = 100; // Max 99. 
    }

    return app_pwm_led_set_config(brightness);
}

int8_t app_pwm_led_control(const uint8_t flag)
{
    /* flag: 0 - stop, 1 -start */
    int8_t ret = 0;
    if(0 == flag){
        if (0 == g_pwm_led_ctx.status) {
            /* already stopped */
            return ret;
        }

        ret = app_pwm_led_set_stop();
        if(0 == ret) {
            g_pwm_led_ctx.status = 0;
            user_post_property();
        }
    } else if(1 == flag){
        LOGD(TAG, "PWM led on.");
        ret = app_pwm_led_set_normal();
        if(0 == ret) {
            g_pwm_led_ctx.status = 1;
            user_post_property();
        }
    } else{
        LOGE(TAG, "flag  %d is incorrect!", flag);
        ret = -1;
    }

    return ret;
}

int8_t app_pwm_led_set_brightness(int32_t brightness)
{
    if (brightness < PWM_LED_LIGHT_MIN) {
        brightness = PWM_LED_LIGHT_MIN;
    } else if (brightness > PWM_LED_LIGHT_MAX) {
        brightness = PWM_LED_LIGHT_MAX;
    }

    if (g_pwm_led_ctx.brightness != brightness) {
        if (aos_kv_setint("led_brightness", brightness) != 0) {
            LOGE(TAG, "set led_brightness failed");
        }
    }

    g_pwm_led_ctx.brightness = brightness;

    return app_pwm_led_control(1);
}

int8_t app_pwm_led_get_brightness()
{
    return g_pwm_led_ctx.brightness;
}

void app_pwm_led_get_rgb(uint8_t *r, uint8_t *g, uint8_t *b)
{
    aos_check_param(r && g && b);

    *r = g_pwm_led_ctx.rgb_val.red;
    *g = g_pwm_led_ctx.rgb_val.green;
    *b = g_pwm_led_ctx.rgb_val.blue;
}

int8_t app_pwm_led_get_status()
{
    return g_pwm_led_ctx.status;
}